package org.com.java_chatroom.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.com.java_chatroom.component.OnlineUserManager;
import org.com.java_chatroom.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

//这个类用来处理消息的发送和接收:
@Component
public class WebSocketAPI extends TextWebSocketHandler {
    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private MessageSessionMapper messageSessionMapper;
    @Autowired
    private MessageMapper messageMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("[webSocketAPI] 连接成功");
//        在注册WebSocket的时候,添加了一个HttpSessionHandshakeInterceptor拦截器,
//        就可以获取到向HttpSession中添加的attribute键值对了:
        User user = (User) session.getAttributes().get("user");
        if(user==null){
            return;
        }
//        设置用户为上线状态:
        onlineUserManager.online(user.getUserId(),session);
    }


    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("[WebSocketAPI] 收到消息:"+message.getPayload());
//        1.获取发送信息的用户信息,进行消息转发
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            System.out.println("[WebSocketAPI] handlerTextMessage :当前用户未登录!");
            return;
        }
//        针对请求进行解析: 将收到的请求字符串 转化成java对象:
        MessageReq req = objectMapper.readValue(message.getPayload(), MessageReq.class);
//        2.进行消息转发:
        if(req.getType().equals("message")){
            transferMessage(user,req);
        }else{
            System.out.println("[WebSocketAPI] 消息类型有误!");
        }

    }
//   这个方法真正进行消息转发工作    参数: 消息发送者       消息对象
    private void transferMessage(User fromUser, MessageReq req) throws IOException {
//      要将这个消息对象转发给当前会话中的所有用户,包括发送者自己:
//      1.根据req获取到sessionId,接着获取到当前会话中的所有用户:
        int sessionId = req.getSessionId();
        List<Friend> list = messageSessionMapper.getFriendsBySessionId(sessionId,fromUser.getUserId());
//        需要将消息也给自己也发送一份,因此需要将self也加入到list中:
        Friend self = new Friend();
        self.setFriendId(fromUser.getUserId());
        self.setFriendName(fromUser.getUsername());
        list.add(self);
//      2.遍历用户列表,将消息发送给所有用户,
//        构造消息响应
        MessageResp resp = new MessageResp();
        resp.setFromId(fromUser.getUserId());
        resp.setFromName(fromUser.getUsername());
        resp.setContent(req.getContent());
        resp.setSessionId(req.getSessionId());
//      将构造好的响应对象先转化成json字符串,用来发送:
        String respJson = objectMapper.writeValueAsString(resp);
        for(Friend f:list){
            WebSocketSession webSocketSession = onlineUserManager.getSession(f.getFriendId());
//        当用户未在线时,则不进行发送,
            if(webSocketSession==null){
                continue;
            }
//          进行消息转发:
            webSocketSession.sendMessage(new TextMessage(respJson));
        }
//      3.将消息存储到数据库中,用来当用户离线后又上线,还可以通过获取历史消息的方式,保证原来的消息还存在:
//        向message表中写入一条消息:
        Message message = new Message();
        message.setFromId(fromUser.getUserId());
        message.setSessionId(req.getSessionId());
        message.setContent(req.getContent());
        int n = messageMapper.add(message);
        if(n!=0){
            System.out.println("[WebSocketAPI] 添加消息成功 n="+n);
        }else{
            System.out.println("[WebSocketAPI] 添加消息失败! ");
        }

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("[WebSocketAPI] 连接异常 ,error:"+exception.toString());
//        设置用户下线:
        User user = (User) session.getAttributes().get("user");
        if(user==null){
            return;
        }
        onlineUserManager.offline(user.getUserId(),session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("[webSocketAPI] 连接关闭 "+session.toString());
        //        设置用户下线:
        User user = (User) session.getAttributes().get("user");
        if(user==null){
            return;
        }
        onlineUserManager.offline(user.getUserId(),session);
    }

}
